package org.eclipse.mylyn.rememberthemilk.core.client;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.mylyn.rememberthemilk.core.RTMLog;
import org.eclipse.mylyn.rememberthemilk.core.exceptions.RTMException;
import org.eclipse.mylyn.rememberthemilk.core.exceptions.RTMLoginException;
import org.eclipse.mylyn.tasks.core.RepositoryStatus;

import com.mdt.rtm.ApplicationInfo;
import com.mdt.rtm.Service;
import com.mdt.rtm.ServiceException;
import com.mdt.rtm.ServiceImpl;
import com.mdt.rtm.data.RtmList;
import com.mdt.rtm.data.RtmLists;
import com.mdt.rtm.data.RtmTaskSeries;
import com.mdt.rtm.data.RtmTasks;
import com.mdt.rtm.data.RtmAuth.Perms;
import com.mdt.rtm.data.RtmTask.Priority;

public abstract class AbstractRTMClient
{

	private final ApplicationInfo appInfo = new ApplicationInfo(
			API_KEY, SHARED_SECRET, NAME);

	private static final String API_KEY = "4abff64579eab56dd6bb4891da2a677a";
	private static final String SHARED_SECRET = "81372f2ad07ceed7";
	private static final String NAME = "MylynRemberTheMilk";

	private static String rtmAuthURL = "https://www.rememberthemilk.com/auth.rtm";

	// protected String username;

	// protected String password;

	// protected String repositoryUrl;

	protected RTMClientData data;

	protected ProxyInfo proxy;

	private Service rtmService;

	private String timeline;

	private String timelineId;

	public AbstractRTMClient(String repositoryUrl, String username,
			String password, ProxyInfo proxy)
	{
		// this.repositoryUrl = repositoryUrl;
		// this.username = username;
		// this.password = password;
		this.proxy = proxy;

		this.data = new RTMClientData();
	}

	public boolean isAuthorized() {
		boolean isAuth;
		try {
			isAuth = getService().isServiceAuthorized();
		} catch (RTMLoginException loginEx) {
			RTMLog.logError(loginEx);
			isAuth = false;
		} catch (ServiceException serviceEx) {
			RTMLog.logError(serviceEx);
			isAuth = false;
		} catch (RTMException rtmEx) {
			RTMLog.logError(rtmEx);
			isAuth = false;
		}
		return isAuth;
	}

	public String beginAuthorization() {
		String authUrl = "";
		try {
			authUrl = getService().beginAuthorization(Perms.delete);
		} catch (RTMLoginException loginEx) {
			RTMLog.logError(loginEx);
		} catch (ServiceException serviceEx) {
			RTMLog.logError(serviceEx);
		} catch (RTMException rtmEx) {
			RTMLog.logError(rtmEx);
		}
		return authUrl;
	}

	public String completeAuthorization() throws CoreException {
		try {
			return getService().completeAuthorization();
		} catch (RTMLoginException e) {
			throw new CoreException(RTMLog.createErrorStatus(
					rtmAuthURL, RepositoryStatus.ERROR_REPOSITORY,
					e.getMessage(), e));
		} catch (ServiceException e) {
			throw new CoreException(RTMLog.createErrorStatus(
					rtmAuthURL, RepositoryStatus.ERROR_REPOSITORY,
					e.getMessage(), e));
		} catch (RTMException e) {
			throw new CoreException(RTMLog.createErrorStatus(
					rtmAuthURL, RepositoryStatus.ERROR_REPOSITORY,
					e.getMessage(), e));
		}
	}

	protected Service getService() throws RTMLoginException, RTMException
	{
		if (rtmService == null)
		{
			try
			{
				ServiceImpl service = new ServiceImpl(appInfo);
				if (proxy != null) {
					service.setHttpProxySettings(proxy.getHost(), proxy.getPort(), proxy.getProxyLogin(), proxy.getProxyPassword());
				}
				rtmService = service;
				if (!rtmService.isServiceAuthorized()) {
//					String url = rtmService.beginAuthorization(Perms.delete);
//					boolean result = WebAuthentication.authenticate(
//							repository_auth_url, this.username, this.password, url);
//					if (!result)
//					{
//						throw new RTMLoginException();
//					}
//
//					rtmService.completeAuthorization();
				}
			} catch (ServiceException srvEx) {
				RTMLog.logError(srvEx);
				throw new RTMLoginException(srvEx.getMessage());
			}
		}
		return this.rtmService;
	}

	protected String getTimeline() throws RTMLoginException, ServiceException, RTMException
	{
		if(timeline == null)
		{
			timeline = this.getService().timelines_create();
		}
		return timeline;
	}

	public boolean hasAttributes()
	{
		return (data.lastUpdate != 0);
	}

	public void updateAttributes(boolean force)
			throws RTMException
	{
		if (!hasAttributes() || force)
		{
			updateAttributes();
			data.lastUpdate = System.currentTimeMillis();
		}
	}

	public abstract void updateAttributes()
			throws RTMException;

	public void setData(RTMClientData data)
	{
		this.data = data;
	}

	public void setProxy(ProxyInfo proxy)
	{
		this.proxy = proxy;
	}

	public ProxyInfo getProxy()
	{
		return proxy;
	}

	public String getRTMListName(String listid) throws RTMException
	{
		RtmLists lists;
		try
		{
			lists = this.getService().lists_getList();
		} catch (ServiceException e)
		{
			throw new RTMException(e.getMessage(), e);
		}


		RtmList rtmlist = lists.getList(listid);
		if(rtmlist != null)
		{
			return rtmlist.getName();
		}
		return "";
	}

	public Map<String, String> getRTMListMap()
	{
		RtmLists lists = data.rtmLists;

		if (lists == null) {
			try {
				updateAttributes();
			} catch (RTMException e) {
				RTMLog.logError(e);
			}
		}

		Map<String, String> list = new LinkedHashMap<String, String>();
		if (lists != null) {
			for (String listId : lists.getLists().keySet())
			{
				RtmList rtmlist = lists.getList(listId);
				list.put(rtmlist.getId(), rtmlist.getName());
			}
		}
		return list;
	}

	public String[] getDefaultStatus() {
		return new String[] { "Incomplete", "Completed" };
	}

	public String[] getPriorities() {

		ArrayList<String> list = new ArrayList<String>(Priority.values().length);

		for (Priority prio : Priority.values())
		{
			list.add(prio.toString());
		}
		return list.toArray(new String[0]);

	}

	public RtmTasks getRTMTasks(String filter) throws RTMException
	{
		RTMLog.logInfo("filter: " + filter);
		RtmTasks lists;
		try
		{
			lists = this.getService().tasks_getList(null, filter, null);
			data.addTasks(lists);
		} catch (ServiceException e)
		{
			throw new RTMException(e.getMessage(), e);
		}
		return lists;
	}

	public RtmTaskSeries getRTMTaskSerie(String serieid )
	{
//		RtmTasks lists;
//		//TODO HACK to get a single instance
//		String filter ="status:completed OR status:incomplete";
//		try
//		{
//			lists = this.getService().tasks_getList(null, filter, null);
//		} catch (ServiceException e)
//		{
//			throw new RTMException(e.getMessage(), e);
//		}
//		for(RtmTaskList taskList : lists.getLists())
//		{
//			for(RtmTaskSeries serie : taskList.getSeries())
//    		 {
//				if(serie.getId().equals(serieid))
//				{
//					return serie;
//				}
//    		 }
//		}
		return data.rtmSeries.get(serieid);
	}

	public RtmTaskSeries updateTaskPriority(String listId, String taskSeriesId, String taskId, Priority priorityValue) {

		RtmTaskSeries series = null;
		try {
			series = getService().tasks_setPriority(timelineId, listId, taskSeriesId, taskId, priorityValue);
			data.rtmSeries.put(series.getId(), series);
		} catch (ServiceException srvEx) {
			String msg = "Unexpected Exception: listId: " + listId +
				", taskSeriesId: " + taskSeriesId + ", taskId: " + taskId;
			RTMLog.log(IStatus.ERROR, IStatus.OK, msg, srvEx);
		} catch (RTMLoginException loginEx) {
			RTMLog.logError(loginEx);
		} catch (RTMException rtmEx) {
			RTMLog.logError(rtmEx);
		}
		return series;
	}

	public void createTimeline() {
		try {
			timelineId = getService().timelines_create();
		} catch (ServiceException srvEx) {
			RTMLog.logError(srvEx);
		} catch (RTMLoginException loginEx) {
			RTMLog.logError(loginEx);
		} catch (RTMException rtmEx) {
			RTMLog.logError(rtmEx);
		}
	}

	public RtmTaskSeries updateTaskName(String listId, String taskSeriesId, String taskId, String newName) {
		RtmTaskSeries series = null;
		try {
			series = getService().tasks_setName(timelineId, listId, taskSeriesId, taskId, newName);
			data.rtmSeries.put(series.getId(), series);
		} catch (ServiceException srvEx) {
			RTMLog.logError(srvEx);
		} catch (RTMLoginException loginEx) {
			RTMLog.logError(loginEx);
		} catch (RTMException rtmEx) {
			RTMLog.logError(rtmEx);
		}
		return series;
	}

	public void updateTaskStatus(String listId, String taskSeriesId, String taskId, boolean isComplete) {
		try {
			RtmTaskSeries series;
			if (isComplete) {
				series = getService().tasks_complete(timelineId, listId, taskSeriesId, taskId);
			} else {
				series = getService().tasks_uncomplete(timelineId, listId, taskSeriesId, taskId);
			}
			data.rtmSeries.put(series.getId(), series);
		} catch (RTMLoginException loginEx) {
			RTMLog.logError(loginEx);
		} catch (ServiceException srvEx) {
			RTMLog.logError(srvEx);
		} catch (RTMException rtmEx) {
			RTMLog.logError(rtmEx);
		}
	}

	public void updateTaskList(String fromListId, String toListId, String taskSeriesId, String taskId) {
		try {
			RtmTaskSeries series = getService().tasks_moveTo(timelineId, fromListId, toListId, taskSeriesId, taskId);
			data.rtmSeries.put(series.getId(), series);
		} catch (RTMLoginException loginEx) {
			RTMLog.logError(loginEx);
		} catch (ServiceException srvEx) {
			RTMLog.logError(srvEx);
		} catch (RTMException rtmEx) {
			RTMLog.logError(rtmEx);
		}
	}

	public RtmTaskSeries createNewTask(String listId, String name) {
		RtmTaskSeries series = null;
		try {
			series = getService().tasks_add(timelineId, listId, name);
			data.rtmSeries.put(series.getId(), series);
		} catch (RTMLoginException loginEx) {
			RTMLog.logError(loginEx);
		} catch (ServiceException srvEx) {
			RTMLog.logError(srvEx);
		} catch (RTMException rtmEx) {
			RTMLog.logError(rtmEx);
		}
		return series;
	}

	public void updateTags(String tags, String listId, String taskSeriesId, String taskId) {
		try {
			RtmTaskSeries series = getService().tasks_addTags(timelineId, listId, taskSeriesId, taskId, tags);
			data.rtmSeries.put(series.getId(), series);
		} catch (RTMLoginException loginEx) {
			RTMLog.logError(loginEx);
		} catch (ServiceException srvEx) {
			RTMLog.logError(srvEx);
		} catch (RTMException rtmEx) {
			RTMLog.logError(rtmEx);
		}
	}

}
